package repository

import (
	"context"
	"errors"
	"fmt"
	"go-pan/internal/model"
	"time"

	"gorm.io/gorm"
)

type FileMetaRepository interface {
	Create(ctx context.Context, meta *model.FileMetadata) error
	FindByID(ctx context.Context, id int64) (*model.FileMetadata, error)
	FindByParent(ctx context.Context, ownerID int64, parentID int64) ([]*model.FileMetadata, error)
	FindByUniqueKey(ctx context.Context, ownerID, parentID int64, nameKey string) (*model.FileMetadata, error)
	FindByHashAndSize(ctx context.Context, hash string, size int64) (*model.FileMetadata, error)
	Delete(ctx context.Context, id int64) error
	HardDelete(ctx context.Context, id int64) error
	Restore(ctx context.Context, id int64) error
	FindDeletedFiles(ctx context.Context, ownerID int64, daysOld int) ([]*model.FileMetadata, error)
	ListDeletedFiles(ctx context.Context, ownerID int64) ([]*model.FileMetadata, error)
	FindAllDeletedFilesOverDays(ctx context.Context, daysOld int) ([]*model.FileMetadata, error)
	Rename(ctx context.Context, id int64, newName, newKey string) error
	Move(ctx context.Context, fileID int64, newParentID int64) error
	HasChildren(ctx context.Context, ownerID int64, parentID int64) (bool, error)
}

type fileMetaRepository struct {
	db *gorm.DB
}

func NewFileMetaRepository(db *gorm.DB) FileMetaRepository {
	return &fileMetaRepository{db: db}
}

func (r *fileMetaRepository) Create(ctx context.Context, meta *model.FileMetadata) error {
	return r.db.WithContext(ctx).Create(meta).Error
}

func (r *fileMetaRepository) FindByID(ctx context.Context, id int64) (*model.FileMetadata, error) {
	var file model.FileMetadata
	if err := r.db.WithContext(ctx).First(&file, id).Error; err != nil {
		return nil, err
	}
	return &file, nil
}

func (r *fileMetaRepository) FindByParent(ctx context.Context, ownerID int64, parentID int64) ([]*model.FileMetadata, error) {
	var files []*model.FileMetadata
	err := r.db.WithContext(ctx).Where("owner_id = ? AND parent_id = ? AND is_deleted = false", ownerID, parentID).Find(&files).Error
	return files, err
}

func (r *fileMetaRepository) FindByUniqueKey(ctx context.Context, ownerID, parentID int64, nameKey string) (*model.FileMetadata, error) {
	var file model.FileMetadata
	err := r.db.WithContext(ctx).
		Where("owner_id = ? AND parent_id = ? AND name_unique_key = ?", ownerID, parentID, nameKey).
		First(&file).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &file, err
}

func (r *fileMetaRepository) Delete(ctx context.Context, id int64) error {
	now := time.Now()
	return r.db.WithContext(ctx).Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"is_deleted": true,
		"deleted_at": now,
	}).Error
}

// HardDelete 彻底删除文件（物理删除）
func (r *fileMetaRepository) HardDelete(ctx context.Context, id int64) error {
	return r.db.WithContext(ctx).Delete(&model.FileMetadata{}, id).Error
}

// Restore 恢复已删除的文件
func (r *fileMetaRepository) Restore(ctx context.Context, id int64) error {
	return r.db.WithContext(ctx).Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"is_deleted": false,
		"deleted_at": nil,
	}).Error
}

// FindDeletedFiles 查找已删除的文件
func (r *fileMetaRepository) FindDeletedFiles(ctx context.Context, ownerID int64, daysOld int) ([]*model.FileMetadata, error) {
	var files []*model.FileMetadata
	cutoffTime := time.Now().AddDate(0, 0, -daysOld)

	err := r.db.WithContext(ctx).
		Where("owner_id = ? AND is_deleted = true AND deleted_at <= ?", ownerID, cutoffTime).
		Find(&files).Error
	return files, err
}

// FindAllDeletedFilesOverDays 查找所有用户中超过指定天数的已删除文件（用于批量清理）
func (r *fileMetaRepository) FindAllDeletedFilesOverDays(ctx context.Context, daysOld int) ([]*model.FileMetadata, error) {
	var files []*model.FileMetadata
	cutoffTime := time.Now().AddDate(0, 0, -daysOld)

	err := r.db.WithContext(ctx).
		Where("is_deleted = true AND deleted_at <= ?", cutoffTime).
		Find(&files).Error
	return files, err
}

// ListDeletedFiles 列出用户所有已删除的文件（用于回收站）
func (r *fileMetaRepository) ListDeletedFiles(ctx context.Context, ownerID int64) ([]*model.FileMetadata, error) {
	var files []*model.FileMetadata
	err := r.db.WithContext(ctx).
		Where("owner_id = ? AND is_deleted = true", ownerID).
		Order("deleted_at DESC").
		Find(&files).Error
	return files, err
}

func (r *fileMetaRepository) Rename(ctx context.Context, id int64, newName, newKey string) error {
	return r.db.WithContext(ctx).Model(&model.FileMetadata{}).Where("id = ?", id).Updates(map[string]interface{}{
		"name":            newName,
		"name_unique_key": newKey,
	}).Error
}

func (r *fileMetaRepository) FindByHashAndSize(ctx context.Context, hash string, size int64) (*model.FileMetadata, error) {
	var file model.FileMetadata
	err := r.db.WithContext(ctx).
		Where("hash_sha256 = ? AND size = ? AND is_deleted = false", hash, size).
		First(&file).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &file, err
}

func (r *fileMetaRepository) HasChildren(ctx context.Context, ownerID int64, parentID int64) (bool, error) {
	var count int64
	if err := r.db.WithContext(ctx).Model(&model.FileMetadata{}).
		Where("owner_id = ? AND parent_id = ? AND is_deleted = false", ownerID, parentID).
		Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

func (r *fileMetaRepository) Move(ctx context.Context, fileID int64, newParentID int64) error {
	// 获取文件信息
	file, err := r.FindByID(ctx, fileID)
	if err != nil {
		return err
	}

	// 计算新的唯一键
	newKey := fmt.Sprintf("%d/%d/%s", file.OwnerID, newParentID, file.Name)

	// 更新 parent_id 和 name_unique_key
	return r.db.WithContext(ctx).Model(&model.FileMetadata{}).Where("id = ?", fileID).Updates(map[string]interface{}{
		"parent_id":       newParentID,
		"name_unique_key": newKey,
	}).Error
}
